#include <stdio.h>
#include <string.h>

/*
  Program to convert the output from the ADC to the
  source voltage and temperature of the processor
*/

/* Converts a binary input to decimal */
int bin2dec(char *bin)
{
  int b, k, n;
  int len, sum = 0;

  len = strlen(bin) - 1; /* Take 1 from the length of the binary string */
  for (k = 0; k <= len; k++)
    { /* Repeats for each digit in the binary number */
    b = 1;
    n = (bin[k] - '0'); /* char to numeric value */

    /* Checks that a binary number has been input */
    if ((n > 1) || (n < 0))
    {
      puts("\n ERROR: Not a binary number\n");
      return (0);
    }

    b = b<<(len-k);
    /* sum it up */
    sum = sum + n * b; /* Adds value of digit to total decimal number. */
  }

  return(sum);
}

void convertDecimal(float vrlow, float vrhigh)
{
  int n;
  float temp, v;

  printf("\nInput decimal value from ADC: ");
  if (scanf("%d",&n)<1) 
    n=-1;
  /* Check input is in range */
  while (getchar()!='\n');
  if (n==-1)
  {
    puts("\n ERROR: Input not decimal");
    return;
  }
  if (n>4095)
  {
    puts("\n ERROR: Value greater than ADC range (max is 4095)");
    return;
  }
  /* Check input is not negative */
  if (n<0)
  {
    puts("\n ERROR: Value must be positive");
    return;
  }
  /* Print hex equivalent */
  printf("Hex = %x\n",n);
  /* Convert to Vin */
  v = n*((vrhigh-vrlow)/4095)+vrlow;
  printf("V ==> %f v\n", v);
  /* Convert to temperature */
  temp=(v-0.986)/0.00355;
  printf("T ==> %f Celcius\n", temp);
}

void convertHex(float vrlow, float vrhigh)
{
  unsigned int n;
  float v, temp;

  printf("\nInput hex value from ADC: ");
  if(scanf("%x",&n)<1) 
    n=-1;
  /* Check input is in range */
  while (getchar()!='\n');
  if (n==-1)
  {
    puts("\n ERROR: Input not a hexadecimal number");
    return;
  }
  if (n>4095)
  {
    puts("\n ERROR: Value greater than ADC range (max is FFF)");
    return;
  }
  /* Print dec equivalent */
  printf("Dec = %d\n",n);
  /* Convert to Vin */
  v = n*((vrhigh - vrlow)/4095)+vrlow;
  printf("V ==> %f v\n", v);
  /* Convert to temperature */
  temp=(v-0.986)/0.00355;
  printf("T ==> %f Celcius\n", temp);
}

void convertBinary(float vrlow, float vrhigh)
{
  char bin[80] = "";
  char *p;
  int dec;
  float v, temp;

  printf("\nInput binary value from ADC: ");
  /* Stores input to a char array */
  fgets(bin, sizeof(bin), stdin);
  /* If there is a gap (/n), removes it */
  if ((p = strchr(bin,'\n')) != NULL)
    *p = '\0';
  /* Converts input to decimal */
  dec = bin2dec(bin);
  /* Print hex and dec equivalents */
  printf("Hex = %x\n",dec);
  if (dec)
    printf("Dec = %d\n",dec);
  /* Convert to Vin */
  v = dec*((vrhigh - vrlow)/4095)+vrlow;
  printf("V ==> %f v\n", v);
  /* Convert to temperature */
  temp = (v-0.986)/0.00355;
  printf("T ==> %f Celcius\n", temp);
}

/* Converts ADC sample for chosen input type and reference voltage */
int main()
{
  int input, ref;
  float vrlow, vrhigh;

  /* Checks that ref is 1 or 2, then sets reference voltages as chosen */
  do
  {
    printf("Select reference voltage - 0-2.5v (1) 0-5v (2) : ");
    scanf("%d", &ref);
    while (getchar()!='\n');
    if (ref!=1 && ref!=2)
      printf(" ERROR: Invalid input\n\n");
  }
  while (ref!=1 && ref!=2);
  if (ref==1)
  {
    vrlow = 0;
    vrhigh = 2.5;
  }
  else
  {
    vrlow = 0;
    vrhigh = 5;
  }
  /* Checks that input is 1 - 3, then runs the chosen conversion function */
  do
  {
    printf("\nSelect input mode - Hex (1) Dec (2) Bin (3) : ");
    scanf("%d", &input);
    while (getchar()!='\n');
    if (input<1 || input>3)
    {
      printf(" ERROR: Invalid input\n");
    }
  }
  while (input<1 || input>3);
  /* Hex */
  if (input==1)
  {
    while(1)
      convertHex(vrlow,vrhigh);
  }
  /* Decimal */
  else if (input==2)
  {
    while(1)
      convertDecimal(vrlow,vrhigh);
  }
  /* Binary */
  else
  {
    while(1)
      convertBinary(vrlow,vrhigh);
  }
}
